<?php

class BaseModel{

    protected $table;

    protected $db = null;

    /**
     * 实例化数据库连接
     * */
    public function __construct() {
        $this->db = PdoBackend::get_instance();
        $this->table = $this->get_table($this->table);
    }

    /**
     * 插入
     * @param array $data
     * @return int last-insert-id
     * */
    public function insert($data) {
        $sql = "INSERT INTO {$this->table}(%s)VALUES(%s)";

        $keys = array_keys($data);
        $values_bind = array();
        foreach($keys as $v) {
            $values_bind[$v] = ":".$v;
        }
        $sql = sprintf($sql, implode(',', $keys), implode(',', $values_bind));
        $binds = array();

        foreach($values_bind as $k=>$v) {
            $binds[$v] = $data[$k];
        }

        $stmt = $this->db->prepare($sql);
        $rs = $stmt->execute($binds);

        return $this->db->lastInsertId();
    }

    /**
     * 编辑
     * @param int $id
     * @param array $data
     * @return boolean
     * */
    public function edit($id, $data) {
        $sql = "UPDATE {$this->table} SET %s WHERE id=%d";

        foreach($data as $k=>$v) {
            $sql_placeholder[] = sprintf("%s=:%s", $k, $k);
            $values_bind[":".$k] = $v;
        }
        $sql = sprintf($sql, implode(",", $sql_placeholder), $id);
        $stmt = $this->db->prepare($sql);
        $rs = $stmt->execute($values_bind);

        return $this->db->lastInsertId();
    }

    /**
     * 多条件更新
     * */
    public function update($condition, $data) {
        $condition = $this->get_condition($condition);
        foreach($data as $k=>$v) {
            if(!$k) {
                continue;
            }
            $update[] = sprintf('%s="%s"', $k, $v);
        }

        if($update) {
            $sql = sprintf("UPDATE {$this->table} SET %s {$condition}", implode(",", $update));
            $this->db->query($sql);
            return $this->db->lastInsertId();
        }

        return true;
    }

    /**
     * 根据单一条件删除
     * */
    public function delete($value, $field="id") {
        $sql = "DELETE FROM {$this->table} WHERE {$field}=:value";
        $stmt = $this->db->prepare($sql);
        return $stmt->execute(array(":value"=> $value));
    }

    /**
     * 执行插入/编辑
     * */
    public function replace($data, $id = 'null', $primary_key = "id") {
        if(!$data[$primary_key] and false !== $id) {
            $data[$primary_key] = $id;
        }
        $sql = "REPLACE INTO {$this->table}(%s)VALUES(%s)";
        $keys = array_keys($data);
        $values_bind = array();
        foreach($keys as $v) {
            $values_bind[$v] = ":".$v;
        }
        $sql = sprintf($sql, implode(',', $keys), implode(',', $values_bind));
        $binds = array();

        foreach($values_bind as $k=>$v) {
            $binds[$v] = $data[$k];
        }

        $stmt = $this->db->prepare($sql);
        $rs = $stmt->execute($binds);

        return $this->db->lastInsertId();
    }

    /**
     * 根据某个单一字段条件获取一条或者多条数据
     * @param string $field
     * @param mixed $value
     * @param boolean $getone
     * @param boolean | integer $cache 是否缓存/缓存存活时间
     * @return array
     * */
    public function get_by($value, $field="id", $getone = true) {
        $sql = "SELECT * FROM `{$this->table}` WHERE %s = '%s'";
        $sql = sprintf($sql, $field, $value);
        
        $method = $getone ? 'fetch' : 'fetchAll';
        $result = $this->db->query($sql);
        if($result) {
            $result = $result->$method(PDO::FETCH_ASSOC);
        }
        return $result;
    }

    /**
     * 获取列表
     * @param array $condition
     * @param string $order
     * @param integer $paginator 分页条数， 为0时不分页
     * */
    public function get_list($condition=array(), $order="id DESC", $table = '') {

        $table = $table ? $this->get_table($table) : $this->table;
        
        $condition_str = $this->get_condition($condition);

        $sql = sprintf("SELECT * FROM {$table} %s", $condition_str, $order);
        if($order) {
            $sql.= " ORDER BY ".$order;
        }
        
        if($rs = $this->db->query($sql)) {
            return $rs->fetchAll(PDO::FETCH_ASSOC);
        }
        
        return array();
    }

    /**
     * 返回表名
     * */
    public function get_table($table = null) {
        if(!$table) {
            return $this->table;
        }
        global $C;
        return $C["database"]["pre"].$table;
    }

    /**
     * 根据数组获取SQL WHERE
     * */
    public function get_condition($condition = array()) {
        $operation = array(
            "!" => "!=",
            ">" => ">",
            "<" => "<",
            "#" => ">=",
            "$" => "<=",
            "^" => " IN "
        );

        $condition_str = " WHERE TRUE";

        if($condition) {
            foreach($condition as $k=>$v) {
                if(!$k) {
                    continue;
                }
                $split = "=";
                if(is_array($v)) {
                    foreach($v as $_k=>$_v) {
                        if(!$_k) {
                            continue;
                        }
                        $_split = "=";
                        if(key_exists($_v{0}, $operation)) {
                            $_split = $operation[$_v{0}];
                            $_v = substr($_v, 1, strlen($_v));
                        }
                        $sub_conditions[] = sprintf("%s%s'%s'", $k, $_split, $_v);
                    }
                } else {
                    if(key_exists($v{0}, $operation)) {
                        $split = $operation[$v{0}];
                        $v = substr($v, 1, strlen($v));
                    }
                    $conditions[] = sprintf("%s%s'%s'", $k, $split, $v);
                }
            }

            $condition_str = '';
            if($sub_conditions) {
                $conditions[] = '('.implode(' OR ', $sub_conditions).')';
            }

            if($conditions) {
                $condition_str = ' WHERE '.implode(" AND ", $conditions);
            }
        }

        $condition_str = str_replace(
            array("'(", ")'"),
            array("(", ")"),
            $condition_str
        );

        return $condition_str;
    }

    public function count($condition = "", $field = "id", $table = "") {
        $condition = is_array($condition) ? $this->get_condition($condition) : $condition;
        
        if($table) {
            global $C;
            if(false === strpos($table, $C["database"]["pre"])) {
                $table = $this->get_table($table);
            } else {
                $table = $table;
            }
        } else {
            $table = $this->table;
        }
        
        $sql = sprintf("SELECT COUNT(%s) AS count FROM {$table} %s", $field, $condition);
        $this->sql = $sql;
        $rs = $this->db->query($sql);
        if(!$rs) {
            return 0;
        }

        $count = $rs->fetch(PDO::FETCH_ASSOC);
        return $count['count'];
    }

}